﻿using System.Linq.Expressions;
using MicroBlog.Data;
using MicroBlog.Infrastructure;
using MicroBlog.Models;
using MicroBlog.ViewModels;
using Microsoft.EntityFrameworkCore;

namespace MicroBlog.Services
{
    public class BlogManager : IBlogManager
    {
        private readonly MicroBlogContext _context;

        public BlogManager(MicroBlogContext context)
        {
            _context = context;
        }

        public async Task<ContextResult> CreateTagAsync(Tag tag)
        {
            _context.Tags.Add(tag);
            await _context.SaveChangesAsync();
            return ContextResult.Success;
        }
        public async Task<IList<TagViewModel>> GetTagsAsync()
        {
            var query = from tag in _context.Tags
                        group tag by tag.Name into g
                        select new TagViewModel
                        {
                            TagName = g.Key,
                            UseCount = g.Count()
                        };
            return await query.ToListAsync();
        }
        public async Task<ContextResult> RemoveTagAsync(string tagName)
        {
            var tags = await _context.Tags.Where(a => a.Name == tagName).ToListAsync();
            if (tags == null)
            {
                return ContextResult.Failed(ErrorDescriber.DataNotFound());
            }
            _context.Tags.RemoveRange(tags);
            await _context.SaveChangesAsync();
            return ContextResult.Success;
        }
        public async Task<ContextResult> UpdateTagAsync(string originTag, string newTag)
        {
            if (originTag != newTag)
            {
                var tags = _context.Tags.Where(w => w.Name == originTag).ToList();
                tags.ForEach(t => t.Name = newTag);
                _context.Tags.UpdateRange(tags);
                await _context.SaveChangesAsync();
            }
            return ContextResult.Success;
        }

        public async Task<IList<TagViewModel>> TagStatisticsAsync()
        {
            var query = from t in _context.Tags
                        group t by t.Name into g
                        orderby g.Count() descending
                        select new TagViewModel
                        {
                            TagName = g.Key,
                            UseCount = g.Count()
                        };
            return await query.ToListAsync();
        }

        public async Task<BlogViewModel> FindAsync(int blogId)
        {
            BlogViewModel blogModel = new BlogViewModel
            {
                Blog = await _context.Blogs.Include(i => i.Tags).Include(i => i.BlogContent).Where(w => w.Id == blogId).FirstOrDefaultAsync(),
                Next = await _context.Blogs.OrderByDescending(o => o.Id).Where(w => w.Id < blogId).FirstOrDefaultAsync(),
                Prev = await _context.Blogs.OrderBy(o => o.Id).Where(w => w.Id > blogId).FirstOrDefaultAsync()
            };
            if (blogModel.Blog != null)
            {
                blogModel.Blog.Views += 1;
                _context.Blogs.Update(blogModel.Blog);
                await _context.SaveChangesAsync();
            }
            return blogModel;
        }
        public async Task<Blog> FirstOrDefaultAsync(int blogId)
        {
            return await _context.Blogs.Include(i => i.Tags).Include(i => i.BlogContent).Where(w => w.Id == blogId).FirstOrDefaultAsync();
        }
        public async Task<ContextResult> RemoveAsync(int blogId)
        {
            var note = await _context.Blogs.Where(w => w.Id == blogId).FirstOrDefaultAsync();
            if (note == null)
            {
                return ContextResult.Failed(ErrorDescriber.DataNotFound());
            }
            _context.Blogs.Remove(note);
            await _context.SaveChangesAsync();
            return ContextResult.Success;
        }
        public async Task<IPagedList<Blog>> SearchAsync(Expression<Func<Blog, bool>> predicate, int pageIndex = 0, int pageSize = int.MaxValue)
        {
            var query = _context.Blogs.Include(i => i.Tags).Where(predicate).OrderByDescending(o => o.Id);
            return await PagedList<Blog>.CreateAsync(query, pageIndex, pageSize);
        }

        public async Task<IPagedList<Blog>> SearchByTagAsync(string tag, int pageIndex = 0, int pageSize = int.MaxValue)
        {
            var query = from p in _context.Blogs.Include(i => i.Tags).OrderByDescending(o => o.Id)
                        join t in _context.Tags on p.Id equals t.BlogId
                        where t.Name == tag
                        select p;
            return await PagedList<Blog>.CreateAsync(query, pageIndex, pageSize);
        }
        /// <summary>
        /// 更新博客
        /// </summary>
        /// <param name="blog"></param>
        /// <returns></returns>
        public async Task<ContextResult> UpdateAsync(Blog blog)
        {
            using (var tr = _context.Database.BeginTransaction())
            {
                try
                {
                    if (blog.Tags.Count > 0)
                    {
                        _context.Tags.RemoveRange(_context.Tags.Where(w => w.BlogId == blog.Id).ToList());
                        _context.SaveChanges();
                    }
                    _context.Blogs.Update(blog);
                    await _context.SaveChangesAsync();
                    tr.Commit();
                }
                catch (Exception ex)
                {
                    tr.Rollback();
                    return ContextResult.Failed(ErrorDescriber.OperateFailed(ex.Message));
                }
            }
            return ContextResult.Success;
        }
        /// <summary>
        /// 写博客
        /// </summary>
        /// <param name="blog"></param>
        /// <returns></returns>
        public async Task<ContextResult> WriteAsync(Blog blog)
        {
            _context.Blogs.Add(blog);
            await _context.SaveChangesAsync();
            return ContextResult.Success;
        }
    }
}
